package laf.socf.simulator.gui;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.ImageIcon;
import laf.socf.simulator.sensors.Sensor;

/**
 *
 * @author L.A. Fernando
 */
public class Robot extends Artifact implements MouseMotionListener, MouseListener {

    public enum DIR {
        UP, LEFT, DOWN, RIGHT
    };
    
    private SimContext context = null;
    private int x,  y;
    private String robotName = null;
    public DIR currentDir = DIR.UP;
    private boolean selected = false;
    private Vector<Sensor> sensors = new Vector<Sensor>();

    public Vector<Sensor> getSensors() {
        return sensors;
    }

    public void setSensors(Vector<Sensor> sensors) {
        this.sensors = sensors;
    }

    public Robot() {
        
    }

    public Robot(SimContext context, String robotName) {
        this.context = context;
        this.robotName = robotName;
        this.setArtifactType(Artifact.TYPE_SOLID);
        this.setToolTipText(this.robotName);
        this.setLocation(100, 100);        
        this.setCurrentDir(DIR.UP);
        this.setSelected(false);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.getFrontObstacleDistance();
    }

    public void startSensors() {
        for (Sensor s : this.getSensors()) {
            s.startSensor();
        }
    }

    public void stopSensors() {
        for (Sensor s : this.getSensors()) {
            s.stopSensor();
        }
    }

    public void setContext(SimContext context) {
        this.context = context;
    }

    public SimContext getContext() {
        return this.context;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
        this.refreshImage();
    }

    public void setRobotName(String robotName) {
        this.robotName = robotName;
    }

    public String getRobotName() {
        return this.robotName;
    }

    private void refreshImage() {
        if (this.currentDir == DIR.UP) {
            if (selected) {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-selected.png")));
            } else {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car.png")));
            }
        } else if (this.currentDir == DIR.DOWN) {
            if (selected) {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-down-selected.png")));
            } else {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-down.png")));
            }
        } else if (this.currentDir == DIR.LEFT) {
            if (selected) {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-left-selected.png")));
            } else {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-left.png")));
            }
        } else if (this.currentDir == DIR.RIGHT) {
            if (selected) {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-right-selected.png")));
            } else {
                this.setIcon(new ImageIcon(getClass().getResource("/images/car-right.png")));
            }
        }
    }

    public void setCurrentDir(DIR currentDir) {
        this.currentDir = currentDir;
        this.refreshImage();
        this.setSize(this.getIcon().getIconWidth(), this.getIcon().getIconHeight());        
    }

    public DIR getCurrentDir() {
        return this.currentDir;
    }

    private boolean intersects(int a1, int a2, int b1, int b2) {
        if ((a1 >= b1 && a1 <= b2) || (a2 >= b1 && a2 <= b2)) {
            return true;
        }
        if ((b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2)) {
            return true;
        }
        return false;
    }

    public String[] getMines() {
        ArrayList<String> list = new ArrayList<String>();
        for (Artifact artifact : this.context.getArtifacts()) {
            if (artifact.getArtifactType() != Artifact.TYPE_MINE) {
                continue;
            }
            if (artifact.getBounds().intersects(this.getBounds())) {
                list.add(artifact.getX() + "," + artifact.getY());                
            }
        }
        String[] strArr = new String[list.size()];
        for (int i = 0; i < strArr.length; i++) {
            strArr[i] = (String) list.get(i);
        }
        return strArr;
    }

    public int getObstacleDistance(DIR dir) {
        int cur = 0, tmp;
        if (dir == DIR.UP) {
            cur = this.context.getHeight() - (this.getY() + this.getHeight());
        } else if (dir == DIR.LEFT) {
            cur = this.context.getWidth() - (this.getX() + this.getWidth());
        } else if (dir == DIR.RIGHT) {
            cur = this.getX();
        } else if (dir == DIR.DOWN) {
            cur = this.getY();
        }
        int myx1, myx2, myy1, myy2, ax1, ax2, ay1, ay2;
        for (Artifact artifact : this.context.getArtifacts()) {
            if (artifact.getArtifactType() != Artifact.TYPE_SOLID) {
                continue;
            }
            myx1 = this.getX();
            myx2 = this.getX() + this.getWidth();
            myy1 = this.getY();
            myy2 = this.getY() + this.getHeight();
            ax1 = artifact.getX();
            ax2 = artifact.getX() + artifact.getWidth();
            ay1 = artifact.getY();
            ay2 = artifact.getY() + artifact.getHeight();
            if (dir == DIR.UP) {
                if (this.intersects(myx1, myx2, ax1, ax2)) {
                    if (ay1 > myy2) {
                        tmp = ay1 - myy2;
                        cur = Math.min(cur, tmp);
                    }
                }
            } else if (dir == DIR.LEFT) {
                if (this.intersects(myy1, myy2, ay1, ay2)) {
                    if (ax1 > myx2) {
                        tmp = ax1 - myx2;
                        cur = Math.min(cur, tmp);
                    }
                }
            } else if (dir == DIR.RIGHT) {
                if (this.intersects(myy1, myy2, ay1, ay2)) {
                    if (myx1 > ax2) {
                        tmp = myx1 - ax2;
                        cur = Math.min(cur, tmp);
                    }
                }
            } else if (dir == DIR.DOWN) {
                if (this.intersects(myx1, myx2, ax1, ax2)) {
                    if (myy1 > ay2) {
                        tmp = myy1 - ay2;
                        cur = Math.min(cur, tmp);
                    }
                }
            }
        }
        return cur;
    }

    public int getFrontObstacleDistance() {
        return this.getObstacleDistance(this.getCurrentDir());
    }

    public int getRightObstacleDistance() {
        int newOrd = this.getCurrentDir().ordinal() - 1;
        if (newOrd < 0) {
            newOrd = 3;
        }
        return this.getObstacleDistance(DIR.values()[newOrd]);
    }

    public void moveRobot() {
        int d = getFrontObstacleDistance();
        if (d > 1) {
            int cx = this.getX();
            int cy = this.getY();
            if (this.currentDir == DIR.UP) {
                this.setLocation(cx, cy + 1);
            } else if (this.currentDir == DIR.LEFT) {
                this.setLocation(cx + 1, cy);
            } else if (this.currentDir == DIR.RIGHT) {
                this.setLocation(cx - 1, cy);
            } else if (this.currentDir == DIR.DOWN) {
                this.setLocation(cx, cy - 1);
            }
        }
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        int dx = (int) e.getPoint().getX() - this.x;
        int dy = (int) e.getPoint().getY() - this.y;
        int cx = (int) this.getLocation().getX();
        int cy = (int) this.getLocation().getY();
        int nx = cx + dx;
        int ny = cy + dy;
        if (nx < 0) {
            nx = 0;
        } else if (nx > context.getWidth() - this.getWidth()) {
            nx = context.getWidth() - this.getWidth();
        }
        if (ny < 0) {
            ny = 0;
        } else if (ny > context.getHeight() - this.getHeight()) {
            ny = context.getHeight() - this.getHeight();
        }
        this.setLocation(nx, ny);
    }

    public void mousePressed(MouseEvent e) {
        x = (int) e.getPoint().getX();
        y = (int) e.getPoint().getY();
        this.setSelected(true);
        this.context.setSelectedRobot(this);
        this.requestFocus();
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
        this.setSelected(false);
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void addSensor(Sensor sensor) {
        this.sensors.add(sensor);
    }

    @Override
    public String toString() {
        String ret = this.getRobotName() + " - Sensors [ ";
        for (int i = 0; i < this.sensors.size(); i++) {
            ret += sensors.get(i).getSensorName();
            if (i + 1 < sensors.size()) {
                ret += ", ";
            }
        }
        ret += " ]";
        return ret;
    }
}
